package server;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * Minicat的主类
 */
public class Bootstrap {

	/** 定义socket监听的端口号 */
	private int port = 8080;
	
	private Map<String, Context> contextMap = new HashMap<String, Context>();

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	/**
	 * Minicat启动需要初始化展开的一些操作
	 */
	public void start() throws Exception {

		// 解析server.xml
		parseConfig();

		// 定义一个线程池
		int corePoolSize = 10;
		int maximumPoolSize = 50;
		long keepAliveTime = 100L;
		TimeUnit unit = TimeUnit.SECONDS;
		BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
		ThreadFactory threadFactory = Executors.defaultThreadFactory();
		RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
				unit, workQueue, threadFactory, handler);

		ServerSocket serverSocket = new ServerSocket(port);
		System.out.println("=====>>>Minicat start on port：" + port);

		System.out.println("=========>>>>>>使用线程池进行多线程改造");
		/*
		 * 多线程改造（使用线程池）
		 */
		while (true) {

			Socket socket = serverSocket.accept();
			RequestProcessor requestProcessor = new RequestProcessor(socket, contextMap);
			// requestProcessor.start();
			threadPoolExecutor.execute(requestProcessor);
		}

	}

	private Map<String, HttpServlet> servletMap = new HashMap<String, HttpServlet>();

	/**
	 * 加载解析web.xml，初始化Servlet
	 */
	private void loadServlet(Context context) {
		InputStream resourceAsStream = context.getWebAppClassLoader().getResourceAsStream("web.xml");
		SAXReader saxReader = new SAXReader();

		try {
			Document document = saxReader.read(resourceAsStream);
			Element rootElement = document.getRootElement();

			List<Element> selectNodes = rootElement.selectNodes("//servlet");
			for (int i = 0; i < selectNodes.size(); i++) {
				Element element = selectNodes.get(i);
				// <servlet-name>lagou</servlet-name>
				Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
				String servletName = servletnameElement.getStringValue();
				// <servlet-class>server.LagouServlet</servlet-class>
				Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
				String servletClass = servletclassElement.getStringValue();

				// 根据servlet-name的值找到url-pattern
				Element servletMapping = (Element) rootElement
						.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
				// /lagou
				String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
				context.getServletMap().put(urlPattern, (HttpServlet) context.getWebAppClassLoader().findClass(servletClass).newInstance());

			}

		} catch (DocumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}
	
	public void parseConfig() {
		InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
		SAXReader saxReader = new SAXReader();
		try {
			Document document = saxReader.read(resourceAsStream);
			Element rootElement = document.getRootElement();
			
			Element connector = (Element) rootElement.selectSingleNode("/Server/Service/Connector");
			String portStr = connector.attributeValue("port");
			if(portStr != null) {
				this.port = Integer.parseInt(portStr);
			}
			
			Element hostElement = (Element) rootElement.selectSingleNode("/Server/Service/Egine/Host");
			String hostName = hostElement.attributeValue("name");
			String appBase = hostElement.attributeValue("appBase");
			Host Host = new Host(hostName, appBase);
			
			loadContext(Host);
			
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		
	}

	public void loadContext(Host host) {
		String appBase = host.getAppBase();
		File file = new File(appBase);
		if(!file.exists()) {
			throw new RuntimeException("指定的appBase不存在："+appBase);
		}
		if(!file.isDirectory()) {
			throw new RuntimeException("指定的appBase不是目录："+appBase);
		}
		
		File[] webapps = file.listFiles();
		for(File webapp:webapps) {
			Context context = new Context(webapp.getName(), host);
			loadServlet(context);
			contextMap.put(context.getAppName(), context);
		}
		
	}
	
	/**
	 * Minicat 的程序启动入口
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		Bootstrap bootstrap = new Bootstrap();
		try {
			// 启动Minicat
			bootstrap.start();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
